<template>
  <div>
    <input type="file" ref="fileInput" multiple @change="fileChange" style="display: none;" />
    <input style="display: none;" type="file" ref="folderInput" webkitdirectory directory multiple
      @change="folderChange" />
    <!-- <NewUploadDialog ref="newUploadDialog" :fileData="dialogFileData" @clearFileData="clearFileDataHandler" /> -->
    <el-dialog v-model="dialogVisible" width="500" :before-close="handleClose">
      <template #header>
        <div style="display: flex;align-items: center;">
          <el-icon>
            <Upload />
          </el-icon>
          <span>上传文件（{{ dialogFile.length }}个）</span>
        </div>
      </template>
      <el-upload class="upload-demo" drag action="#" multiple :auto-upload="false" :file-list="dialogFile"
        :on-change="handleChange" :on-remove="handleRemove">
        <el-icon class="el-icon--upload"><upload-filled /></el-icon>
        <div class="el-upload__text">
          将文件拖到此处或 <em>点击上传</em>
        </div>

      </el-upload>
      <!-- <div class="disc">
        <div style="margin-bottom: 6px;">描述</div>
        <el-input v-model="textarea" :rows="2" type="textarea" placeholder="请输入描述" />
      </div> -->
      <div class="checkBox" v-if="isShowTip">
        <el-checkbox v-model="isChecked" label="1" size="large">
          是否同步到问答库中
          <el-tooltip content="TXT、MARKDOWN、PDF、HTML、XLSX、XLS、DOCX、CSV、MD、HTM" placement="top">
            <el-icon>
              <InfoFilled />
            </el-icon>
          </el-tooltip>
        </el-checkbox>
        <!-- <el-checkbox v-if="isChecked" v-model="isOcr" label="1" size="large">
          是否使用OCR服务（只能解析PDF文件）
        </el-checkbox> -->
      </div>
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="dialogVisible = false">取消</el-button>
          <el-button type="primary" @click="hanldeUpload">
            确定
          </el-button>
        </div>
      </template>
    </el-dialog>
    <el-dialog v-model="folderDia" title="上传文件夹" width="500" :before-close="folderClose">
      <el-button type="primary" @click="enterpriseFolder.click()" :disabled="fileBoxList.length > 0">选择文件夹</el-button>
      <input style="display: none;" type="file" ref="enterpriseFolder" webkitdirectory directory multiple
        @change="enterpriseFolderChange" />
      <div class="fileBox">
        <div class="file_list_box" v-for="(item, index) in fileBoxList" :key="index">
          <div class="file_list_wai">
            <div class="file_list">
              <div class="file_name">
                <el-tooltip class="item" effect="dark" :content="item.webkitRelativePath" placement="top">
                  <span>{{ item.webkitRelativePath }}</span>
                </el-tooltip>
              </div>
              <div class="file_size1">
                {{ formatSize(item.loaded) + '/' + formatSize(item.size) }}
              </div>

              <div v-if="item.status == 'waiting'" class="file_size">
                等待中...
              </div>
              <div v-if="item.status == 'uploading'" class="file_size">
                上传中...
              </div>
              <div v-if="item.status == 'success'" class="file_size" style="color:#67C23A;">
                上传成功
              </div>
              <div v-if="item.status == 'failed'" class="file_size" style="color:#F56C6C;">
                上传失败
              </div>
              <div class="file_hand" v-if="!loading" @click="deleteUploadListClick(item, index)">
                <el-icon>
                  <Close />
                </el-icon>
              </div>
            </div>
          </div>
          <div class="file_status">
            <el-progress :show-text="true" :percentage="item.progress" :stroke-width="5"></el-progress>
          </div>
        </div>
      </div>
      <div class="checkBox" v-if="isShowTip">
        <el-checkbox v-model="isChecked" label="1" size="large" :disabled="loading">
          是否同步到问答库中
          <el-tooltip content="TXT、MARKDOWN、PDF、HTML、XLSX、XLS、DOCX、CSV、MD、HTM" placement="top">
            <el-icon>
              <InfoFilled />
            </el-icon>
          </el-tooltip>
        </el-checkbox>
        <!-- <el-checkbox v-if="isChecked" v-model="isOcr" label="1" size="large">
          是否使用OCR服务（只能解析PDF文件）
        </el-checkbox> -->
      </div>
      <template #footer>
        <div class="dialog-footer" v-if="!isAllUpload">
          <el-button @click="folderClose">取消</el-button>
          <el-button type="primary" @click="sureEnterpriseFolder" :loading="loading">
            确定
          </el-button>
        </div>
        <div class="dialog-footer" v-else>
          <el-button type="primary" @click="folderClose">关闭</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>



<script lang="ts" setup>
import { ref, reactive } from 'vue'
// import NewUploadDialog from '@/views/components/newUploadDialog/index.vue';
import { v4 as uuidv4 } from 'uuid'
import { checkOss, createFileChunk } from '@/api/system/oss'
import axios from 'axios'
import { getToken } from '@/utils/auth'
import { apiGetEnterpriseFilesTreeIsKnowLab } from '@/api/enterpriseDoc/enterpriseDocApi'
import { useUploadDialogStore } from '@/store/modules/uploadDialog'
import { getFileMd5, uploadSliceFunc } from "@/utils/getFileMd5"


const dialogStore = useUploadDialogStore()
const fileInput = ref(null)
const folderInput = ref(null)
const enterpriseFolder = ref(null)
const newUploadDialog = ref(null)
const fileBoxList = ref([])
const loading = ref(false)

const isChecked = ref(false)
// const isOcr = ref(false);
const isShowTip = ref<boolean>(false);;

const dialogVisible = ref(false)
const folderDia = ref(false)  // 文件夹
const dialogFile = ref([])


// 维护正在上传的文件数量
const activeUploads = ref(0)
const maxConcurrentUploads = ref(1) // 限制同时上传的文件数量
const uploadedCount = ref(0) // Number of uploaded files
const totalFilesToUpload = ref(0) // Total number of files to upload

const isAllUpload = ref(false) // 是否全部上传完成

// 待上传文件列表
const uploadingQueue = ref([])
// 选中的文件夹信息
const treeFolderData = ref<treeFolderType>({ type: '', parentId: null, libraryId: null })
//上传弹窗展示的文件列表
const dialogFileData = ref<(FileItem | FolderItem)[]>([])
const folderTotalSize = ref(null)  // 文件夹中文件总大小
const folderToUpload = ref(0) // 文件夹中待上传文件数量
const totalUploadedSize = ref(0) // 文件夹中已上传文件大小
const evPath = import.meta.env.VITE_APP_BASE_API
const uploadedChunksMap = ref({})  // 大文件分片时，记录已上传的分片
const totalSlices = ref(0) // 文件分片总数
const isUploadFile = ref(false) // 是否正在上传文件


const emit = defineEmits(['uploadSuccess'])
const { proxy } = getCurrentInstance() as any

// 基本数据
const data = reactive({
  fileTotalSize: 0,
  isUploading: false
})

// 定义选中文件夹数据
interface treeFolderType {
  type: string
  parentId: number
  libraryId?: number,
  teamId?: number
}


// 定义文件属性
interface FileItem {
  typeName?: string
  file: File
  parentId: number
  id: string
  name?: string
  size: number
  suffix: string
  progress: number
  loaded?: number // 已上传大小
  status: string
}
// 文件夹中文件属性
interface FolderItem {
  typeName: string
  id: string
  folderName: string
  size: number
  progress: number
  status: string
  type: string
  loaded?: number
  children: FileItem[]
}





// 文件带下格式化
const formatSize = (size: number) => {
  return proxy.$yuUtils.filterSizeUnit(size)
}

// 触发文件上传
const triggerFile = (data: treeFolderType) => {
  treeFolderData.value = data
  if (treeFolderData.value.type === 'enterprise') {
    dialogVisible.value = true

    nextTick(() => {
      isChecked.value = false
      // isOcr.value = false;
      dialogFile.value = []  // Clear after the dialog is rendered
      getCheckBox()  // Any other logic you need to run
    })

  } else {
    fileInput.value?.click()
  }
}
// 触发文件夹上传
const triggerFolder = (data: treeFolderType) => {
  treeFolderData.value = data
  if (treeFolderData.value.type === 'enterprise') {
    getCheckBox()
    folderDia.value = true
    loading.value = false
    isAllUpload.value = false

  } else {
    folderInput.value?.click()
  }

}

// 企业获取checkBox
const getCheckBox = async () => {
  const res: any = await apiGetEnterpriseFilesTreeIsKnowLab({
    baseId: treeFolderData.value.libraryId
  })
  if (res.code == 200) {
    isShowTip.value = res.data
  }
}

// 企业文件弹窗
const handleChange = (file: any) => {
  dialogFile.value.push(file)
}
const handleRemove = (file: any) => {
  const index = dialogFile.value.indexOf(file)
  if (index > -1) {
    dialogFile.value.splice(index, 1)
  }
}


// 企业上传文件
const hanldeUpload = async () => {
  // Proceed to upload after validation
  dialogVisible.value = false
  uploadedCount.value = 0
  totalFilesToUpload.value = dialogFile.value.length
  folderToUpload.value = dialogFile.value.length
  // Loop through each file and upload it
  for (let i = 0; i < dialogFile.value.length; i++) {
    const file = dialogFile.value[i]
    const fileId = uuidv4() // Generate a unique ID for the file
    const fileItem: FileItem = {
      typeName: 'file',
      file: file.raw, // Access the raw file data
      id: fileId,
      parentId: treeFolderData.value.parentId,
      name: file.name,
      size: file.size,
      suffix: file.name.split('.').pop() || '',
      progress: 0, // Initial progress (0%)
      status: 'waiting' // Initial status
    }
    if (fileItem.suffix === 'exe' || fileItem.size === 0) {
      fileItem.progress = 0 // 设置文件上传状态为 failed
      fileItem.status = 'failed' // 设置文件上传状态为 failed
      dialogFileData.value.push(fileItem) // 记录失败的文件
      dialogStore.openDialog(dialogFileData) // 打开上传对话框
      return // 跳过该文件的上传
    }

    // Check if the file data is valid
    const isValid = await checkData(fileItem)
    if (isValid) {
      // Add file to the uploading queue
      uploadingQueue.value.push(fileItem)

      dialogFileData.value.push(fileItem)

      // Open dialog with the list of files
      dialogStore.openDialog(dialogFileData)

      // If this is the first file being uploaded, start processing the upload queue
      if (uploadingQueue.value.length > 0) {
        processQueue() // Handle the file upload queue
      }
    }
  }

}

// 企业文件夹上传
const enterpriseFolderChange = (e: Event) => {
  const fileEvent = e.target as HTMLInputElement
  if (fileEvent.files) {
    fileBoxList.value = Array.from(fileEvent.files)
    // totalFilesToUpload.value = fileBoxList.value.length;
    // folderToUpload.value = fileBoxList.value.length
    fileBoxList.value.forEach((file: any) => {
      if (file.size == 0) {
        file.status = 'failed'
        file.progress = 0
        file.loaded = 0
        ElMessage.error('文件不能为空')
        return
      }
      // file.file = file;
      file.id = uuidv4()
      file.status = 'waiting' // 上传状态
      file.progress = 0 // 上传进度
      file.loaded = 0 // 已上传大小
    })
  }
}


// 取消单个文件上传
const deleteUploadListClick = (item: any, index: number) => {
  fileBoxList.value.splice(index, 1)
  // totalFilesToUpload.value = fileBoxList.value.length;
}

// 企业文件夹上传
const sureEnterpriseFolder = () => {
  uploadedCount.value = 0
  loading.value = true
  fileBoxList.value.forEach(async (file: any) => {
    const fileData = {
      typeName: 'folder',
      file: file,
      parentId: treeFolderData.value.parentId,
      id: file.id,
      name: file.name,
      size: file.size,
      suffix: file.name.split('.').pop() || '',
      progress: 0, // 上传进度
      loaded: 0, // 已上传大小
      status: 'uploading' // 上传状态
    }
    if (fileData.suffix === 'exe' || fileData.size === 0) {
      fileData.progress = 0 // 设置文件上传状态为 failed
      fileData.status = 'failed' // 设置文件上传状态为 failed
      dialogFileData.value.push(fileData) // 记录失败的文件
      const isFailed = fileBoxList.value.every((item: any) => item.status === 'failed')
      if (isFailed) {
        isAllUpload.value = true
      }
      // dialogStore.openDialog(dialogFileData) // 打开上传对话框
      return // 跳过该文件的上传
    }
    const validFiles = fileBoxList.value.filter(
      (file: any) => file.size > 0 && file.name.split('.').pop() !== 'exe'
    )
    totalFilesToUpload.value = validFiles.length


    const isValid = await checkData(fileData)
    if (isValid) {
      uploadingQueue.value.push(fileData)
      if (uploadingQueue.value.length === 1) {
        processQueue()
      }
    }

  })

}

// 关闭文件夹上传弹窗
const folderClose = () => {
  fileBoxList.value = []
  enterpriseFolder.value.value = ''
  loading.value = false
  isChecked.value = false
  folderDia.value = false
  isAllUpload.value = false
}




// 文件上传
const fileChange = async (e: Event) => {
  const fileEvent = e.target as HTMLInputElement
  if (fileEvent.files) {
    const files = Array.from(fileEvent.files)
    fileEvent.value = '' // 清空文件输入框
    uploadedCount.value = 0
    totalFilesToUpload.value = files.length
    folderToUpload.value = files.length

    // Collect valid file items in an array
    const validFileItems: FileItem[] = []

    for (const file of files) {
      const fileId = uuidv4() // 生成文件唯一标识
      data.fileTotalSize += file.size // 上传文件总大小
      const fileItem: FileItem = {
        typeName: 'file',
        file: file,
        id: fileId,
        parentId: treeFolderData.value.parentId,
        name: file.name,
        size: file.size,
        suffix: file.name.split('.').pop() || '',
        progress: 0, // 上传进度
        loaded: 0, // 已上传大小
        status: 'waiting' // 上传状态
      }

      if (fileItem.suffix === 'exe' || fileItem.size === 0) {
        fileItem.progress = 0 // 设置文件上传状态为 failed
        fileItem.status = 'failed' // 设置文件上传状态为 failed
        dialogFileData.value.push(fileItem) // 记录失败的文件
        dialogStore.openDialog(dialogFileData) // 打开上传对话框
        continue // Skip this file
      }

      const isValid = await checkData(fileItem) // Validate the file
      if (isValid) {
        validFileItems.push(fileItem) // Collect valid file items
      }
    }

    // Add all valid files to the queue in one batch
    if (validFileItems.length > 0) {
      uploadingQueue.value.push(...validFileItems)
      // console.log('上传文件', uploadingQueue.value) // Log all valid files
      dialogFileData.value.push(...validFileItems) // Add files to the dialog
      dialogStore.openDialog(dialogFileData) // Open upload dialog
      processQueue() // Process the upload queue
    }
  }
}


// 验证数据是否正确
const checkData = async (fileItem: FileItem) => {
  try {
    const res = await checkOss({
      fileSize: fileItem.size,
      fileName: fileItem.name,
      fileSuffix: fileItem.name.split('.').pop() || '',
      type: treeFolderData.value.type,
      parentId: treeFolderData.value.parentId,
      // teamId: treeFolderData.value.teamId
    })

    if (res.code == 200) {
      return true // Validation successful, proceed with upload
    } else {
      // Handle failed validation, e.g., show an error message
      return false // Don't upload this file
    }
  } catch (error) {
    console.error('Error during validation:', error)
    return false // Handle any errors during the validation process
  }
}
// 文件上传队列
const processQueue = async () => {
  // 如果队列不为空，并且没有文件正在上传，则处理队列中的第一个文件
  if (uploadingQueue.value.length > 0) {
    const fileItem = uploadingQueue.value.shift() // 从队列中取出一个文件
    // console.log('上传文件', fileItem) // Log remaining files in the queue
    fileItem.status = 'uploading' // 更改文件状态为上传中
    // 根据文件类型选择上传函数
    if (treeFolderData.value.type === 'enterprise' && fileItem.typeName === 'folder') {
      await uploadEnterpriseFile(fileItem) // 上传企业文件
    } else {
      await uploadFile(fileItem) // 上传普通文件
    }
    // 上传完成后，递归调用 processQueue 处理下一个文件
    processQueue()
  }
}


// 上传文件
const uploadFile = async (fileItem: FileItem) => {
  if (fileItem.typeName === 'file') {
    if (fileItem.size > 1024 * 1024 * 20) {
      await uploadLargeFile(fileItem) // 分片上传大文件
    } else {
      // dialogFileData.value.push(fileItem);
      await uploadSmallFile(fileItem) // 上传小文件
    }
  } else {
    if (fileItem.size > 1024 * 1024 * 20) {
      // await uploadLargeFolder(fileItem)
      await uploadLargeFile(fileItem) // 分片上传大文件
    } else {
      await uploadSmallFolder(fileItem)
    }
  }
}
// 上传小文件
const uploadSmallFile = async (fileItem: FileItem) => {
  const formData = new FormData()
  formData.append('file', fileItem.file)
  formData.append('parentId', fileItem.parentId.toString())
  formData.append('type', treeFolderData.value.type)
  formData.append('fileName', fileItem.file.name.split('.')[0])
  formData.append('unzip', 'true')
  if (treeFolderData.value.type === 'team') {
    formData.append('teamId', treeFolderData.value.teamId.toString())
  }
  let obJson = {
    isKnowledge: isChecked.value,
    // isOcr: isOcr.value,
  }
  formData.append('info', JSON.stringify(obJson))
  try {
    // const res = await uploadOrdinary(fomrData)
    const res = await axios.post(`${evPath}/resource/oss/file/date/upload/ordinary`, formData, {
      headers: {
        'Content-Type': 'multipart/form-data',
        'Authorization': 'Bearer ' + getToken(),
      },
      onUploadProgress: (progressEvent) => {
        const progress = Math.round((progressEvent.loaded / progressEvent.total) * 100)
        const findIndex = dialogFileData.value.findIndex((item) => item.id === fileItem.id)
        if (findIndex !== -1) {
          dialogFileData.value[findIndex].progress = progress < 100 ? progress : 99
          // dialogFileData.value[findIndex].loaded = progressEvent.loaded; // 更新已上传大小
          if (progress < 100) {
            dialogFileData.value[findIndex].status = 'uploading'
          }
        }
      }

    })
    if (res.data.code == 200) {
      const findIndex = dialogFileData.value.findIndex((item) => item.id === fileItem.id)
      if (findIndex !== -1) {
        // Set progress to 100% and mark as success
        dialogFileData.value[findIndex].progress = 100
        dialogFileData.value[findIndex].status = 'success'
      }
      uploadedCount.value++


      if (uploadedCount.value === totalFilesToUpload.value) {
        emit('uploadSuccess') // Trigger only once after all files are uploaded
      }
    }
    else {
      const findIndex = dialogFileData.value.findIndex((item) => item.id === fileItem.id)
      if (findIndex !== -1) {
        dialogFileData.value[findIndex].status = 'failed' // 更新上传状态
        dialogFileData.value[findIndex].progress = 0 // 更新上传进度
      }
      ElMessage.error(res.data.msg)
    }
    // console.log(res, '123');
  } catch (error) {
    console.log(error)
  }
}

// 分片上传大文件
const uploadQueue = []
let isUploading = false
const uploadLargeFile = async (fileItem: FileItem) => {
  uploadQueue.push(fileItem)
  if (isUploading) return // 防止并发循环
  isUploading = true

  while (uploadQueue.length > 0) {
    const currentFile = uploadQueue.shift()
    await processUpload(currentFile)
    if (fileItem.typeName === 'file') {
      await new Promise((resolve) => {
        const unsubscribe = watch(
          () => {
            const fileIndex = dialogFileData.value.findIndex((item) => item.id === currentFile.id)
            if (fileIndex !== -1) {
              const curFile = dialogFileData.value[fileIndex]
              return curFile.progress === 100 && curFile.status === 'success'
            }
            return false
          },
          (isComplete) => {
            if (isComplete) {
              unsubscribe() // 停止监听
              resolve(true) // 继续下一步
            }
          },
          { immediate: true }
        )
      })
    }
  }

  isUploading = false
}


const processUpload = async (fileItem: FileItem) => {

  const file = fileItem.file
  const size = file.size // 文件大小
  const chunkSize = 5 * 1024 * 1024 // 每片5MB
  const chunkCount = Math.ceil(size / chunkSize) // 分片数量
  if (fileItem.typeName === 'folder') {
    totalSlices.value += chunkCount
  } else {
    totalSlices.value = chunkCount
  }

  const fileMd5 = await getFileMd5(file, chunkCount) // 计算文件 MD5 值
  const fileName = file.name.substring(0, file.name.lastIndexOf("."))
  const fileParts = file.name.split(".")
  const fileSuffix = fileParts[fileParts.length - 1]
  const isFolder = fileItem.typeName === 'folder'
  const formData = new FormData()

  // 设置文件夹路径（仅文件夹上传需要）
  if (isFolder) {
    const relativePath = fileItem.file.webkitRelativePath
    const filePath = relativePath.split("/").slice(0, -1).join("/")
    formData.append('filePath', filePath)
  }
  let obJson = {
    isKnowledge: isChecked.value,
    // isOcr: isOcr.value,
  }
  formData.append('info', JSON.stringify(obJson))

  // 基础参数
  formData.append('file', file)
  formData.append('parentId', fileItem.parentId.toString())
  formData.append('type', treeFolderData.value.type)
  formData.append('fileName', fileName)
  formData.append('fileMd5', fileMd5)
  formData.append('suffix', fileSuffix)
  formData.append('fileSize', size.toString())
  formData.append('partSize', chunkSize.toString())


  const res = await createFileChunk(formData)
  const promiseAllList = []

  if (res.code === 200) {
    for (let i = 0; i < chunkCount; i++) {
      const start = i * chunkSize
      const end = Math.min(size, start + chunkSize)
      const _chunkFile = file.slice(start, end)
      const currentFile = new File([_chunkFile], file.name, { type: file.type, lastModified: file.lastModified })
      const currentFileMd5 = await getFileMd5(currentFile, chunkCount)

      const chunkFormData = new FormData()
      if (isFolder) {
        const relativePath = fileItem.file.webkitRelativePath
        const filePath = relativePath.split("/").slice(0, -1).join("/")
        chunkFormData.append('filePath', filePath)
      }

      chunkFormData.append("partNumber", (i + 1).toString())
      chunkFormData.append("partMd5", currentFileMd5)
      chunkFormData.append("fileMd5", fileMd5)
      chunkFormData.append("file", currentFile)
      chunkFormData.append("parentId", fileItem.parentId.toString())
      chunkFormData.append("type", treeFolderData.value.type)
      chunkFormData.append("fileName", fileName)
      chunkFormData.append("suffix", fileSuffix)
      chunkFormData.append("fileSize", size.toString())
      chunkFormData.append("sliceId", res.data.sliceId)
      chunkFormData.append("isFolder", isFolder.toString()) // 区分文件和文件夹
      chunkFormData.append("unzip", 'true')

      promiseAllList.push(chunkFormData)
    }

    // 执行分片上传
    concurrencyRequestFile(promiseAllList, 3, fileItem)
  }
}





const uploadQueueEn = []
let isUploadingEn = false
// 企业上传文件夹
const uploadEnterpriseFile = async (fileItem: FileItem) => {
  if (fileItem.size < 1024 * 1024 * 20) {
    const relativePath = fileItem.file.webkitRelativePath
    const filePath = relativePath.split("/").slice(0, -1).join("/")
    const formData = new FormData()
    formData.append('file', fileItem.file)
    formData.append('filePath', filePath)
    formData.append('parentId', fileItem.parentId.toString())
    formData.append('type', treeFolderData.value.type)
    formData.append("extend", treeFolderData.value.type === "team" ? '0' : "")
    formData.append('fileName', fileItem.file.name.split('.')[0])
    let obJson = {
      isKnowledge: isChecked.value,
      // isOcr: isOcr.value,
    }
    formData.append('info', JSON.stringify(obJson))
    try {
      const res = await axios.post(`${evPath}/resource/oss/file/date/upload/ordinary`, formData, {
        headers: {
          'Content-Type': 'multipart/form-data',
          'Authorization': 'Bearer ' + getToken(),
        },
        onUploadProgress: (progressEvent) => {
          const progress = Math.round((progressEvent.loaded / progressEvent.total) * 100)
          const findIndex = fileBoxList.value.findIndex((item) => item.id === fileItem.id)
          if (findIndex !== -1) {
            const updatedItem = { ...fileBoxList.value[findIndex] }
            updatedItem.size = progressEvent.total
            updatedItem.webkitRelativePath = fileItem.file.webkitRelativePath
            updatedItem.loaded = Math.min(progressEvent.loaded, updatedItem.size)
            updatedItem.progress = progress
            updatedItem.status = progress < 100 ? 'uploading' : 'success'
            fileBoxList.value[findIndex] = updatedItem

          }
        }
      })

      if (res.data.code === 200) {
        uploadedCount.value++ // 增加已上传文件数量
        const findIndex = fileBoxList.value.findIndex((item) => item.id === fileItem.id)
        if (findIndex !== -1) {
          // Set progress to 100% and mark as success
          const updatedItem = { ...fileBoxList.value[findIndex] }
          updatedItem.progress = 100
          updatedItem.status = 'success'
          fileBoxList.value[findIndex] = updatedItem

          if (uploadedCount.value === totalFilesToUpload.value) {
            // loading.value = false;
            isAllUpload.value = true // 所有文件上传完成
            emit('uploadSuccess')
          }
        }

      } else {
        uploadedCount.value++ // 增加已上传文件数量
        const findIndex = fileBoxList.value.findIndex((item) => item.id === fileItem.id)
        if (findIndex !== -1) {
          const updatedItem = { ...fileBoxList.value[findIndex] }
          updatedItem.status = 'exception' // 更新上传状态
          updatedItem.progress = 0 // 更新上传进度
          updatedItem.loaded = 0 // 更新已上传大小
          fileBoxList.value[findIndex] = updatedItem
          if (uploadedCount.value === totalFilesToUpload.value) {
            // loading.value = false;
            isAllUpload.value = true // 所有文件上传完成
            emit('uploadSuccess')
          }
        }
        //   loading.value = false;
        //   isAllUpload.value = false;
        ElMessage.error(res.data.msg)
      }
    } catch (error) {
      console.log(error)
    }
  } else {
    uploadQueueEn.push(fileItem)
    if (isUploadingEn) return // 防止并发循环
    isUploadingEn = true

    while (uploadQueueEn.length > 0) {
      const currentFile = uploadQueueEn.shift()
      await processUpload(currentFile)
      if (fileItem.typeName === 'file') {
        await new Promise((resolve) => {
          const unsubscribe = watch(
            () => {
              const fileIndex = dialogFileData.value.findIndex((item) => item.id === currentFile.id)
              if (fileIndex !== -1) {
                const curFile = dialogFileData.value[fileIndex]
                return curFile.progress === 100 && curFile.status === 'success'
              }
              return false
            },
            (isComplete) => {
              if (isComplete) {
                unsubscribe() // 停止监听
                resolve(true) // 继续下一步
              }
            },
            { immediate: true }
          )
        })
      }
    }

    isUploadingEn = false
  }
}





// 文件夹上传
const folderChange = (e: Event) => {
  uploadedCount.value = 0
  folderTotalSize.value = 0 // 重置文件夹总大小
  folderToUpload.value = 0 // 重置文件待上传数量
  totalUploadedSize.value = 0 // 重置已上传文件总大小
  const fileEvent = e.target as HTMLInputElement
  const folderId = uuidv4() // 生成文件夹唯一标识
  if (fileEvent.files) {
    const files = Array.from(fileEvent.files)
    fileEvent.value = '' // 清空文件输入框
    const folderChildren: FileItem[] = []

    const relativePath = files[0].webkitRelativePath
    const folderName = relativePath.split('/')[0]

    files.forEach(async (file) => {


      // folderToUpload.value++

      const fileItem: FileItem = {
        typeName: 'folder',
        id: folderId, // 唯一的 ID
        name: file.name, // 文件名
        size: file.size, // 文件大小
        suffix: file.name.split('.').pop() || '', // 文件后缀
        progress: 0, // 初始上传进度
        status: 'uploading', // 上传状态
        file: file, // 保留原始 File 对象
        parentId: treeFolderData.value.parentId, // 父文件夹 ID
      }

      if (fileItem.suffix === 'exe' || fileItem.size === 0) {
        fileItem.progress = 0 // 设置文件上传状态为 failed
        fileItem.status = 'failed' // 设置文件上传状态为 failed
        // dialogFileData.value.push(fileItem) // 记录失败的文件
        dialogStore.openDialog(dialogFileData) // 打开上传对话框

        return // 跳过该文件的上传
      }
      folderToUpload.value++
      folderTotalSize.value += file.size


      const isValid = await checkData(fileItem)
      if (isValid) {
        // newUploadDialog.value?.showProgress(); // 打开文件进度弹窗
        folderChildren.push(fileItem) // 将文件添加到文件夹的 children 数组
        uploadingQueue.value.push(fileItem)
        if (uploadingQueue.value.length > 0) {
          processQueue() // 处理上传队列
        }
      }
    })
    const folderItem: FolderItem = {
      typeName: 'folder',
      id: folderId,
      folderName: folderName, // 文件夹名称
      children: folderChildren, // 包含所有文件的 children 数组
      size: files.reduce((total, file) => total + file.size, 0), // 计算文件夹总大小
      progress: 0, // 文件夹的上传进度
      type: 'folder',
      status: 'uploading', // 文件夹的上传状态
    }
    if (folderItem.size > 200 * 1024 * 1024) {
      ElMessage.error('文件夹大小不能超过200M')
    } else {
      // newUploadDialog.value?.showProgress();
      dialogFileData.value.push(folderItem) // 将文件夹添加到 dialogFileData 数组
      dialogStore.openDialog(dialogFileData)
    }
  }
}


// 小文件夹上传
const uploadSmallFolder = async (fileItem: FileItem) => {
  // console.log(fileItem.size, 'fileItem')
  const relativePath = fileItem.file.webkitRelativePath
  const filePath = relativePath.split("/").slice(0, -1).join("/")
  const formData = new FormData()
  formData.append('file', fileItem.file)
  formData.append('filePath', filePath)
  formData.append('parentId', fileItem.parentId.toString())
  formData.append('type', treeFolderData.value.type)
  formData.append("extend", treeFolderData.value.type === "team" ? '0' : "")
  formData.append('fileName', fileItem.file.name.split('.')[0])
  try {
    const res = await axios.post(`${evPath}/resource/oss/file/date/upload/ordinary`, formData, {
      headers: {
        'Content-Type': 'multipart/form-data',
        'Authorization': 'Bearer ' + getToken(),
      },
      onUploadProgress: (progressEvent) => {
        const fileUploadedSize = progressEvent.loaded
        totalUploadedSize.value += fileUploadedSize
        const folderProgress = Math.min(
          Math.round((totalUploadedSize.value / folderTotalSize.value) * 100),
          99
        )

        const findIndex = dialogFileData.value.findIndex((item) => item.id === fileItem.id)
        // console.log(findIndex, 'findIndex')
        // console.log(folderProgress, 'folderProgress')
        if (findIndex !== -1) {
          dialogFileData.value[findIndex].progress = folderProgress < 100 ? folderProgress : 99
          // console.log(dialogFileData.value[findIndex], 'dialogFileData')
          if (folderProgress < 100) {
            dialogFileData.value[findIndex].status = 'uploading'
          }
        }
      }
    })

    if (res.data.code === 200) {
      uploadedCount.value++
      // console.log(uploadedCount.value, 'uploadedCount')
      // console.log(folderToUpload.value, 'folderToUpload')
      if (uploadedCount.value === folderToUpload.value) {
        const findIndex = dialogFileData.value.findIndex((item) => item.id === fileItem.id)
        if (findIndex !== -1) {
          dialogFileData.value[findIndex].status = 'success'
          dialogFileData.value[findIndex].progress = 100
        }
        emit('uploadSuccess') // Trigger only once after all files are uploaded
      }
    }
  } catch (error) {
    console.log(error)
  }


}

// 关闭弹窗
const handleClose = () => {
  dialogVisible.value = false
}


const concurrencyRequestFile = (arrlist: FormData[], maxNum: number, fileItem: FileItem): Promise<any[]> => {
  return new Promise((resolve, reject) => {
    if (arrlist.length === 0) {
      resolve([])
      return
    }

    const results: (any | null)[] = new Array(arrlist.length).fill(null) // 初始化结果数组
    let completedCount = 0 // 已完成请求数
    let activeCount = 0 // 当前活动请求数
    let hasErrorOccurred = false // 是否发生错误

    // 内部函数：发起请求
    const launchRequests = async (index: number): Promise<void> => {
      if (index >= arrlist.length || hasErrorOccurred) return // 如果请求完成或出错，则停止

      activeCount++
      try {
        const formDataParams = arrlist[index]
        const resp = await getMethods(formDataParams, fileItem) // 执行单个请求
        results[index] = resp // 存储请求结果
      } catch (err) {
        results[index] = err
        hasErrorOccurred = true
        reject(err) // 如果发生错误，拒绝 Promise
        return
      } finally {
        completedCount++
        activeCount--

        if (completedCount === arrlist.length) {
          resolve(results) // 全部请求完成时，解析 Promise
        } else if (!hasErrorOccurred) {
          // 当一个请求完成后，继续处理下一个
          launchRequests(completedCount + activeCount)
        }
      }
    }

    // 启动请求，最多 `maxNum` 个并发
    for (let i = 0; i < maxNum && i < arrlist.length; i++) {
      launchRequests(i)
    }
  })
}

const getMethods = (fomrData: FormData, fileItem: FileItem) => {
  if (!uploadedChunksMap[fileItem.id]) {
    uploadedChunksMap[fileItem.id] = 0
  }
  return new Promise((resolve, reject) => {
    axios.post(`${evPath}/resource/oss/file/date/upload/slice`, fomrData, {
      headers: {
        'Content-Type': 'multipart/form-data',
        'Authorization': 'Bearer ' + getToken(),
      },
      onUploadProgress: (progressEvent) => {
        const chunkProgress = Math.round((progressEvent.loaded / progressEvent.total) * 100)
        if (chunkProgress === 100) {
          uploadedChunksMap[fileItem.id]++
        }
        if (treeFolderData.value.type === 'enterprise' && fileItem.typeName === 'folder') {
          const findIndex = fileBoxList.value.findIndex((item) => item.id === fileItem.id)
          // console.log(findIndex, 'findIndex')
          console.log(progressEvent.loaded, 'progressEvent.loaded')
          if (findIndex !== -1) {
            if (!uploadedChunksMap[fileItem.id]) {
              uploadedChunksMap[fileItem.id] = 0 // 初始化已上传大小
            }

            uploadedChunksMap[fileItem.id] += progressEvent.loaded

            const loadedSize = Math.min(uploadedChunksMap[fileItem.id], fileItem.size)
            let fileProgress = Math.floor((loadedSize / fileItem.size) * 95)
            fileProgress = Math.min(fileProgress, 95)
            const updatedItem = { ...fileBoxList.value[findIndex] }
            updatedItem.size = fileItem.size
            updatedItem.webkitRelativePath = fileItem.file.webkitRelativePath
            updatedItem.loaded = loadedSize
            updatedItem.progress = fileProgress
            updatedItem.status = fileProgress < 100 ? 'uploading' : 'success'
            fileBoxList.value[findIndex] = updatedItem
          }
        } else {
          const fileIndex = dialogFileData.value.findIndex((item) => item.id === fileItem.id)
          if (fileIndex !== -1) {
            const fileItem = dialogFileData.value[fileIndex]
            let fileProgress = Math.floor((uploadedChunksMap[fileItem.id] / totalSlices.value) * 95)
            fileProgress = Math.min(fileProgress, 95)
            fileItem.progress = fileProgress
            fileItem.status = 'uploading'
          }

        }
      }
    })
      .then((res) => {
        if (res.data.code === 200 && res.data.data == '上传文件成功') {
          uploadedCount.value++
          if (treeFolderData.value.type === 'enterprise' && fileItem.typeName === 'folder') {
            // uploadedCount.value++
            const findIndex = fileBoxList.value.findIndex((item) => item.id === fileItem.id)
            if (findIndex !== -1) {
              // Set progress to 100% and mark as success
              const updatedItem = { ...fileBoxList.value[findIndex] }
              updatedItem.progress = 100
              updatedItem.status = 'success'
              fileBoxList.value[findIndex] = updatedItem
              if (uploadedCount.value === totalFilesToUpload.value) {
                // loading.value = false;
                isAllUpload.value = true // 所有文件上传完成
                emit('uploadSuccess')
              }
            }
          } else {
            if (fileItem.typeName === 'file') {
              const fileIndex = dialogFileData.value.findIndex((item) => item.id === fileItem.id)

              if (fileIndex !== -1) {
                const curFile = dialogFileData.value[fileIndex]
                curFile.progress = 100
                curFile.status = 'success'
              }
              if (uploadedCount.value === totalFilesToUpload.value) {
                emit('uploadSuccess')
              }
            } else {

              if (uploadedCount.value === folderToUpload.value) {
                const fileIndex = dialogFileData.value.findIndex((item) => item.id === fileItem.id)
                if (fileIndex !== -1) {
                  const curFolder = dialogFileData.value[fileIndex]
                  curFolder.progress = 100
                  curFolder.status = 'success'
                }
                emit('uploadSuccess')
              }
            }
            totalSlices.value = 0
          }
        } else if (res.data.code == 500) {
          // const fileIndex = dialogFileData.value.findIndex((item) => item.id === fileItem.id)
          // if (fileIndex !== -1) {
          //   dialogFileData.value[fileIndex].status = 'failed' // 更新上传状态
          //   dialogFileData.value[fileIndex].progress = 0 // 更新上传进度
          // }
          ElMessage.error(res.data.msg)
        }
        resolve(res)
      }).catch((err) => {
        reject(err)
        ElMessage.error(err.msg)
      })
  })
}


defineExpose({
  triggerFile,
  triggerFolder
});

</script>

<style lang="scss" scoped>
//在全局设置
input[aria-hidden=true] {
  display: none !important;
}

.fileBox {
  .file_list_wai {
    .file_list {
      height: 55px;
      display: flex;
      align-items: center;
      justify-content: space-between;


      .file_name {
        width: 50%;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
      }

      .file_hand {
        cursor: pointer;
        color: #ff4d4f;
      }
    }
  }

  .file_status {
    border-bottom: 1px solid #e0e0e0;
    padding-bottom: 10px;
  }
}
</style>
